/*version 20141002*/
/*固定48个字节留下，每个头有24个字节，但在arm下估计是12个字节*/
/*ARM下非对齐访问是不允许的 x86允许  */

#include "MC.h"
#include <compile.h>
//#include "uartStdio.h"

#include "OSProc.h"


#define 	u32			_ptlong
#define		u8			unsigned char
#define		FLPAGE_SIZE		(16*1024)	//16 KB
#define		PAGE_SIZE		(4*1024)	//4 KB
#define		SLPAGE_SIZE		(1*1024)   //1 KB
#define 	FLPAGE_BLANK		(1 << 14)  //2^14 ALIGN, TTB0 3~13 reseverd
#define		SLPAGE_BLANK		(1 << 12)  //2^12 ALIGN
#define		PAGE_BLANK		    (4*1024)   //4KB  ALIGN
#define		LOW(n)			(0xFFFFFFFF >> n)
#define		HIGH(n)			(0xFFFFFFFF << n)
#define 	HWREG(x)                        (*((volatile _ptlong *)(x)))

#define		_FIND_PRE_NEAR(x,__ALIGN__)	(_ptlong)(((_ptlong)(x)) - ((((_ptlong)(x)) % (_ptlong)(__ALIGN__))))
#define		_FIND_FOL_NEAR(x,__ALIGN__)			\
  (_ptlong)(((x) % (__ALIGN__)) == 0				\
	    ? ((x))						\
	    : ((x) + ((__ALIGN__) - ((x) % (__ALIGN__)))))

//#define     _FIND_PRE_NEAR(x,y)     ((((_ptlong)(x))%y == 0)?((_ptlong)(x)):((((_ptlong)(x))/y)*y))
//#define     _FIND_FOL_NEAR(x,y)     ((((_ptlong)(x))%y == 0)?((_ptlong)(x)):((((_ptlong)(x))/y + 1)*y))

#define NOW				(((_tcb*)(run->content))->pPro)
#define NOWT				((_tcb*)(run->content))
#define	__DSB()		__asm__ __volatile__("DSB;")
#define	__DMB()		__asm__ __volatile__("DMB;")
#define	__ISB()		__asm__ __volatile__("ISB;")

extern volatile _klock kernellock;
extern volatile ring* run;
extern volatile ring* sleep;

#define CONFLICT_AREA(x)			do	\
{							\
	if(x == &kmemory)				\
	{						\
		KERNEL_MUTEX_Lock((_klock*)&kernellock,(ring*)run);	\
	}						\
	else						\
	{						\
		MUTEX_LOCK(&(x->locker));		\
	}						\
}while(0);

#define NO_CONFLICT_AREA(x)			do	\
{							\
	if(x == &kmemory)				\
	{						\
		KERNEL_MUTEX_UnLock((_klock*)&kernellock,(ring*)run);	\
	}						\
	else						\
	{						\
		MUTEX_UNLOCK(&(x->locker));		\
	}						\
}while(0);



extern volatile _mch kmemory;


void MemoryControlInit(_mch* handle,_ptlong* memoryBase,_ptlong memorySize)
{
	if (handle == NULL) return;
	handle->MEMORY_BASE = memoryBase;
	handle->MEMORY_SIZE = memorySize;
	handle->next = (_mcb*)memoryBase;
//first memory block init
	handle->next->used = 0;
	handle->next->msize = memorySize - sizeof(_mcb);
	handle->next->next = NULL;
	if(handle != &kmemory)
	{
		MUTEX_Init(&(handle->locker));
	}

}
void* Kmalloc(_mch* handle,_ptlong size)
{
	_ptlong l = size % 4;
	if(l != 0)
	{
		return (void*)Kalloc(handle,size + ( 4 - l ));
	}
	else
	{
		return (void*)Kalloc(handle,size);
	}
}


void* Kalloc(_mch* handle,_ptlong size)
{
	volatile _mcb* pointer = handle->next;
	volatile _mcb* prepointer = NULL;
//Danger Area


CONFLICT_AREA(handle)
	while(pointer != NULL)
	{
		if(pointer->used == 0 && pointer->msize >= size /*+ sizeof(_mcb) + sizeof(_ptlong)*/)
		{
			pointer->used = 1;
			break;
		}
		prepointer = pointer;
		pointer = pointer->next;
	}
//Danger Area out
NO_CONFLICT_AREA(handle);
	if(pointer !=NULL)
	{
		if(pointer->msize <= size + sizeof(_mcb))
		{
            pointer->used = 1;
			return (((u8*)pointer)+sizeof(_mcb));
		}

		//I find one big
		u8* buff = (u8*)pointer;
		buff += size + sizeof(_mcb);
		_mcb* newpointer = (_mcb*)buff;



		newpointer->used = 0;
		newpointer->msize = pointer->msize - size - sizeof(_mcb);
		newpointer->next = pointer->next;


		pointer->used = 1;
		pointer->msize = size;
		pointer->next = newpointer;


		buff = ((u8*)pointer) + sizeof(_mcb);
		return (void*)buff;
	}
	else
	{



		MemoryFlash(handle);


		pointer = handle->next;
		prepointer = (_mcb*)handle;
//Danger Area
CONFLICT_AREA(handle);
		while(pointer != NULL)
		{
			if(pointer->used == 0 && pointer->msize >= size /*+ sizeof(_mcb) + sizeof(_ptlong)*/)
			{
				pointer->used = 1;
				break;
			}
			prepointer = pointer;
			pointer = pointer->next;
		}
//Danger Area Out
NO_CONFLICT_AREA(handle);
		if(pointer !=NULL)
		{

			if(pointer->msize <= size + sizeof(_mcb))
			{
            pointer->used = 1;
			return (((u8*)pointer)+sizeof(_mcb));
			}

			//I find one big
			u8* buff = (u8*)pointer;
			buff += size + sizeof(_mcb);
			_mcb* newpointer = (_mcb*)buff;



			newpointer->used = 0;
			newpointer->msize = pointer->msize - size - sizeof(_mcb);
		        newpointer->next = pointer->next;


			pointer->used = 1;
			pointer->msize = size;
			pointer->next = newpointer;


			buff = ((u8*)pointer) + sizeof(_mcb);
			return (void*)buff;
		}
		else return NULL;
	}
}


void MemoryFlash(_mch* handle)
{
	_mcb* prepointer = handle->next;
	_mcb* pointer = prepointer->next;
	if(pointer == NULL)
		return;
CONFLICT_AREA(handle);
	while(pointer != NULL)
	{
		if(pointer->used == 0 && prepointer->used == 0)
		{//Combine!
			_mcb* buff = pointer;
			prepointer->msize += pointer->msize + sizeof(_mcb);
			prepointer->next = buff->next;
			pointer = prepointer->next;
		}
		else
		{
			prepointer = pointer;
			pointer = pointer->next;
		}
	}
NO_CONFLICT_AREA(handle);

}

void Kfree(_mch* handle, void* pointer)//? why need handle?
{
	u8* buff = (u8*)pointer;
	buff -= sizeof(_mcb);
	_mcb* bpointer = (_mcb*)buff;
	bpointer->used = 0;

}

static void* _PageApply(_mch* handle,_ptlong Pagesize,_ptlong ALIGN)
{
		MemoryFlash(handle);

		_ptlong targetBegin;
		_ptlong targetEnd;

		 volatile _mcb* pointer = handle->next;

//Danger Area
CONFLICT_AREA(handle);
		while( pointer != NULL)//problems!!
		{
			targetBegin = (((_ptlong)pointer) + sizeof(_mcb));
			targetEnd   = (((targetBegin)) + pointer->msize) ;

					if((pointer->used == 0)
					   &&(pointer->msize >= Pagesize)
					   &&((targetBegin = _FIND_FOL_NEAR(targetBegin,ALIGN)) 
					      < (targetEnd = _FIND_PRE_NEAR(targetEnd,ALIGN))))
					{pointer->used = 1;break;}
			pointer = pointer->next;
		}

//Danger Area out
NO_CONFLICT_AREA(handle);

		if(pointer == NULL) return NULL;
		volatile _mcb* re = (_mcb*)(targetBegin - sizeof(_mcb));
		re->next = pointer->next;
		pointer->next = (decltype(pointer->next))re;

		re->used = (_ptlong)1;

				_ptlong size = (_ptlong)pointer + (_ptlong)pointer->msize ;/* + sizeof(_mcb)*/
				size -= ((_ptlong)re + (_ptlong)Pagesize);/*+ sizeof(_mcb)*/

				if( size <= sizeof(_mcb))
				{

					pointer-> msize = (_ptlong)pointer->msize - (_ptlong)sizeof(_mcb) - (_ptlong)(Pagesize + size) ;
					re->msize = (_ptlong)(Pagesize + size);
				}
				else
				{
					 u8* newbuff = (u8*)re;
					newbuff += Pagesize + sizeof(_mcb);
					_mcb* buff = (_mcb*)newbuff;

					(buff ->used) = 1;						//problems!
					(buff ->msize) = (_ptlong)size - (_ptlong)sizeof(_mcb);			//problems!

					pointer ->msize = pointer->msize - sizeof(_mcb) - (_ptlong)Pagesize - sizeof(_mcb) - buff->msize;
					buff ->next = re -> next;
					re->next = buff;

					(re->used) = 1;
					(re->msize) = (_ptlong)Pagesize;
					buff->used = 0;



				}
		pointer->used = 0;
			__DSB();//?


    return (void*)(((u8*)re) + sizeof(_mcb));

}


inline void* FLPageApply(_mch* handle) //pretested
{
	return	_PageApply(handle,FLPAGE_SIZE,FLPAGE_BLANK);
}
inline void* SLPageApply(_mch* handle) //pretested
{
	return	_PageApply(handle,SLPAGE_SIZE,SLPAGE_BLANK);
}
void* PageApply(_ptlong pagenum,_mch* handle) //pretested //4KB ALIGN
{
	_ptlong realsize = pagenum * PAGE_SIZE;
	return	_PageApply(handle,realsize,PAGE_BLANK);
}

void* KMemoryFixed(_mch* handle, void* pointer, _ptlong msize)//No tested
{/*
	_mcb* preblock = NULL;		//reconnect
	_mcb* changingblock = handle->next;
	pointer = ((char*)pointer) - sizeof(_mcb);
	msize += sizeof(_mcb);
	void* endpointer = (void*)(((_ptlong)pointer) + msize + sizeof(_mcb));
//OnLock
CONFLICT_AREA(handle);
	while(changingblock->msize + ((_ptlong)changingblock) + sizeof(_mcb) < ((_ptlong)pointer))
	{
		preblock = changingblock;
		changingblock = changingblock->next;
	}

	_mcb* endingblock = changingblock;

	while(endingblock->msize + ((_ptlong)endingblock) + sizeof(_mcb) < ((_ptlong)endpointer))
	{
		endingblock = endingblock->next;
	}
	_mcb* newblock = pointer;
	endpointer = (void*)(((_ptlong)pointer) + msize);
	if(endpointer != endingblock)
	{//Fix
		_mcb* endingnextblock = endingblock->next;
		_ptlong used = endingblock->used;
		_ptlong m_size = (_ptlong)endingnextblock - (_ptlong)endpointer - sizeof(_mcb);
		endingblock = endpointer;
		endingblock->next = endingnextblock;
		endingblock->used = used;
		endingblock->msize = m_size;
	}
	newblock->msize = msize - sizeof(_mcb);
	newblock->used = 1;
	newblock->next = endingblock;
	preblock->next = newblock;
	preblock->msize =((_ptlong)newblock) - ((_ptlong)preblock) - sizeof(_mcb); 
NO_CONFLICT_AREA(handle);
	return (void*)(((char*)pointer) + sizeof(_mcb));
*/
	return NULL;
} 
